package cn.edu.nju.ws.sview.reasoning;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import cn.edu.nju.ws.sview.cache.URIIDCache;
import cn.edu.nju.ws.sview.cache.URILabelCache;
import cn.edu.nju.ws.sview.rdf.BlankNode;
import cn.edu.nju.ws.sview.rdf.Literal;
import cn.edu.nju.ws.sview.rdf.RDFDocument;
import cn.edu.nju.ws.sview.rdf.Resource;
import cn.edu.nju.ws.sview.rdf.URIResource;
import cn.edu.nju.ws.sview.reasoning.provenance.FromRDFDocument;
import cn.edu.nju.ws.sview.reasoning.provenance.FromReasoning;
import cn.edu.nju.ws.sview.reasoning.provenance.Provenance;

/**
 * Ground atom
 * 
 * @author Gong Cheng
 * @author Gong Saisai
 * 
 */
public class GroundAtom extends Atom<Constant> {
	private Provenance provenance = null;
	/**
	 *ground atom
	 * 
	 * @param predicate
	 *            ground atom predicate
	 * @param constants
	 *            ground atom constant
	 * @param provenance
	 *           ground atom provenance
	 */
	public GroundAtom(Predicate predicate, ArrayList<Constant> constants,
			Provenance provenance) {
		super(predicate, constants);
		this.provenance = provenance;
	}

	/**
	 * 
	 * @return  ground atom provenance
	 */
	public Provenance getProvenance() {
		return this.provenance;
	}
	
    public String ShowProvenance(String lang) throws SQLException {
		StringBuffer sb = new StringBuffer();
		List<GroundAtom> list = new LinkedList<GroundAtom>();
		// Although show the provenance in a way user can understand, the order
		// of the body literals may be different from the original rule
		list.add(this);
		while (list.size() > 0) {
			GroundAtom item = list.remove(0);
			if(item.getPredicate().getArity()==1){
				sb.append(this.getTermLabel(item.get(0),lang)+" is of type "+this.getPredicateLabel(item.getPredicate(),lang)) ;
			}else{
				sb.append(this.getTermLabel(item.get(0),lang)+" "+this.getPredicateLabel(item.getPredicate(),lang)+" "+this.getTermLabel(item.get(1),lang));
			}
			sb.append(" holds since: <br>"+item.getProvenanceExplanation(lang) + "<br>");
			sb.append("<br>") ;
			if (item.getProvenance() instanceof FromReasoning) {
				FromReasoning prov = (FromReasoning) item.getProvenance();
				ArrayList<GroundAtom> mList = prov.getGroundAtoms();
				for (int i = 0; i < mList.size(); i++) {
					list.add(mList.get(i));
				}
			}
		}
		return sb.toString();
	}
	
	private String getProvenanceExplanation(String lang) throws SQLException {
		StringBuffer sb = new StringBuffer();
		if(this.provenance instanceof FromRDFDocument){
			FromRDFDocument docProv = (FromRDFDocument)this.provenance;
			RDFDocument doc = docProv.getRDFDocument();
			sb.append("&nbsp;&nbsp;&nbsp;Direct assertion in source \""+this.getResourceLabel(doc.getURI(),lang)+"\"") ;
		}
		else if (this.provenance instanceof FromReasoning){
			FromReasoning reasonProv = (FromReasoning)this.provenance;
			Rule rule = reasonProv.getRule();
			ArrayList<Atom<Term>> body = rule.getBody();
			Atom<Term> head = rule.getHead();
			sb.append("Rule:<br>&nbsp;&nbsp;&nbsp;If ");
			for(int i=0;i<body.size();i++){
				Atom<Term> atom = body.get(i) ;
				if(atom.getPredicate().getArity()==1){
					sb.append(this.getTermLabel(atom.get(0),lang)+" is of type "+this.getPredicateLabel(atom.getPredicate(),lang)) ;
				}else{
					sb.append(this.getTermLabel(atom.get(0),lang)+" "+this.getPredicateLabel(atom.getPredicate(),lang)+" "+this.getTermLabel(atom.get(1),lang));
				}
				if(i!=body.size()-1)
					sb.append(" and ") ;
			}
			sb.append(" , then ");
			if(head.getPredicate().getArity()==1){
				sb.append(this.getTermLabel(head.get(0),lang)+" is of type "+this.getPredicateLabel(head.getPredicate(),lang)) ;
			}else{
				sb.append(this.getTermLabel(head.get(0),lang)+" "+this.getPredicateLabel(head.getPredicate(),lang)+" "+this.getTermLabel(head.get(1),lang));
			}
			sb.append("<br>Because<br>&nbsp;&nbsp;&nbsp;");
			ArrayList<GroundAtom> factsDepended = reasonProv.getGroundAtoms();
			for(int j=0;j<factsDepended.size();j++){
				GroundAtom atom = factsDepended.get(j) ;
				if(atom.getPredicate().getArity()==1){
					sb.append(this.getTermLabel(atom.get(0),lang)+" is of type "+this.getPredicateLabel(atom.getPredicate(),lang)) ;
				}else{
					sb.append(this.getTermLabel(atom.get(0),lang)+" "+this.getPredicateLabel(atom.getPredicate(),lang)+" "+this.getTermLabel(atom.get(1),lang));
				}
				if(j!=factsDepended.size()-1)
					sb.append(" and ") ;
			}
			sb.append(" holds <br>Therefore<br>&nbsp;&nbsp;&nbsp;");{
			if(this.getPredicate().getArity()==1){
					sb.append(this.getTermLabel(this.get(0),lang)+" is of type "+this.getPredicateLabel(this.getPredicate(),lang)) ;
				}else{
					sb.append(this.getTermLabel(this.get(0),lang)+" "+this.getPredicateLabel(this.getPredicate(),lang)+" "+this.getTermLabel(this.get(1),lang));
				}	
			}
		}
		return sb.toString();
	}
	
	private String getPredicateLabel(Predicate pred,String lang) throws SQLException{
		Resource res = pred.getResource();
		return this.getResourceLabel(res,lang) ;
	}
	
	private String getResourceLabel(Resource res,String lang) throws SQLException{
		String s = null;
		if(res instanceof URIResource){
			URIResource uriRes  = ((URIResource)res);
			String label = null;
			try {
				int uri_id = URIIDCache.getInstance().getURIID(uriRes.getURI(), true);
				label = URILabelCache.getInstance().getLabel(uri_id, lang);
			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if(label ==null||label.equals(""))
				label = uriRes.getURI();
              s = "<i>"+label+"</i>" ;
		}else if(res instanceof BlankNode){
			BlankNode blanknode = ((BlankNode)res);
			String label = blanknode.getLabel(lang);
			if(label ==null||label.equals(""))
				label = blanknode.toString();
			s = "<i>"+label+"</i>";
		}else{
			Literal literal = ((Literal)res);
			String label = literal.getLexicalForm();
			if(label ==null||label.equals(""))
				label = literal.toString();
			s = "<i>"+label+"</i>";
		}
		return s;
	}
	
    private String getTermLabel(Term term,String lang) throws SQLException{
    	String s = null;
    	if(term instanceof Variable){
    		s = ((Variable)term).toString();
    	}else{
    		Resource res = ((Constant)term).getResource();
    		s = this.getResourceLabel(res,lang);
    	}
    	return s;
    }
	
	public void setProvenance(Provenance prov){
		this.provenance = prov;
	}
}